#include "UdxDataApi.h"
#include "nxdat.h"
#include "nxdat.mini.api.h"

#include <string.h>
#include <vector>
#include <Windows.h>
#include "tinyxml2.h"

namespace NGIS
{
	namespace Data
	{
		const dxftable_t* dxftable;

		extern "C" NGISDATA_API int NGISDATA_CALLCONV getVersion()
		{
			return 20;
		}

		extern "C" NGISDATA_API int NGISDATA_CALLCONV createUdxDataset(const char* pName)
		{
			dxftable = nx_get_dxftable_mini(0);
			dx_object_t* dx=dxftable->fn_dx_object_create("", nxid("dataset"), dxnode, 0);
			//addNode((int)(dx->node), "sss", dxint, 1);

			return (int)dx;
		}

		extern "C" NGISDATA_API int NGISDATA_CALLCONV getDatesetNode(int dxObj)
		{
			dx_object_t* realDx = (dx_object_t*)dxObj;
			return (int)(realDx->node);
		}

		extern "C" NGISDATA_API int NGISDATA_CALLCONV addNode(int parentNode, const char* name, int type, int length)
		{
			dx_node_t* realParentNode = (dx_node_t*)parentNode;
			e_dx_type_t nodeType = (e_dx_type_t)type;

			dx_node_t* node = realParentNode->dxobject->dxftable->fn_node_add_child
				(realParentNode, nxid(name), nodeType, length);

			return (int)node;
		}

		extern "C" NGISDATA_API void NGISDATA_CALLCONV releaseUdxDataset(int dxObj)
		{
			dx_object_t* realDx = (dx_object_t*)dxObj;
			dxftable->fn_dx_object_release(realDx);
		}

		extern "C" NGISDATA_API int NGISDATA_CALLCONV getCellLength(int node)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			int valLen = dxftable->fn_node_get_data_cell(realNode).length;
			return valLen;
		}


		//////////////////////////////////////////////////////////////////////////
		extern "C" NGISDATA_API bool NGISDATA_CALLCONV setNodeIntValue(int node, int value)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxint || cellLen != 1)
				return false;
			else
				*cell.iVal = value;
			return true;
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV setNodeRealValue(int node, double value)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxreal || cellLen != 1)
				return false;
			else
				*cell.rVal = value;
			return true;
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV setNodeStringValue(int node, const char* value)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxstring || cellLen != 1)
				return false;
			else
			{
				realNode->dxobject->dxftable->fn_put_string(realNode, value, 0);
			}
			return true;
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV setNodeVector2dValue(int node, double x, double y)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxvector2 || cellLen != 1)
				return false;
			else
			{
				cell.vec2[0].x=x;
				cell.vec2[0].y=y;
			}
			return true;
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV setNodeVector3dValue(int node, double x, double y, double z)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxvector3 || cellLen != 1)
				return false;
			else
			{
				cell.vec3[0].x=x;
				cell.vec3[0].y=y;
				cell.vec3[0].z=z;
			}
			return true;
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV setNodeVector4dValue(int node, double x, double y, double z, double m)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxvector4 || cellLen != 1)
				return false;
			else
			{
				cell.vec4[0].x=x;
				cell.vec4[0].y=y;
				cell.vec4[0].z=z;
				cell.vec4[0].w=m;
			}
			return true;
		}

		//////////////////////////////////////////////////////////////////////////
		extern "C" NGISDATA_API bool NGISDATA_CALLCONV addNodeIntArrayValue(int node, int idx, int value)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxint || cellLen <= 1 || idx<0 || idx>=cellLen)
				return false;
			else
				cell.iVal[idx] = value;
			return true;
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV addNodeRealArrayValue(int node, int idx, double value)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxreal || cellLen <= 1 || idx<0 || idx>=cellLen)
				return false;
			else
				cell.rVal[idx] = value;
			return true;
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV addNodeStringArrayValue(int node, int idx, const char* value)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxstring || cellLen <= 1 || idx<0 || idx>=cellLen)
				return false;
			else
			{
				realNode->dxobject->dxftable->fn_put_string(realNode, value, idx);
			}
			return true;
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV addNodeVector2dArrayValue(int node, int idx, double x, double y)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxvector2 || cellLen <= 1 || idx<0 || idx>=cellLen)
				return false;
			else
			{
				cell.vec2[idx].x=x;
				cell.vec2[idx].y=y;
			}
			return true;
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV addNodeVector3dArrayValue(int node, int idx, double x, double y, double z)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxvector3 || cellLen <= 1 || idx<0 || idx>=cellLen)
				return false;
			else
			{
				cell.vec3[idx].x=x;
				cell.vec3[idx].y=y;
				cell.vec3[idx].z=z;
			}
			return true;
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV addNodeVector4dArrayValue(int node, int idx, double x, double y, double z, double m)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxvector4 || cellLen <= 1 || idx<0 || idx>=cellLen)
				return false;
			else
			{
				cell.vec4[idx].x=x;
				cell.vec4[idx].y=y;
				cell.vec4[idx].z=z;
				cell.vec4[idx].w=m;
			}
			return true;
		}

		//////////////////////////////////////////////////////////////////////////
		extern "C" NGISDATA_API int NGISDATA_CALLCONV getNodeIntValue(int node)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxint || cellLen != 1)
				return 0;
			else 
				return cell.iVal[0];
		}

		extern "C" NGISDATA_API double NGISDATA_CALLCONV getNodeRealValue(int node)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxreal || cellLen != 1)
				return 0;
			else 
				return cell.rVal[0];
		}

		extern "C" NGISDATA_API const char* NGISDATA_CALLCONV getNodeStringValue(int node)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxstring || cellLen != 1)
				return 0;
			else 
			{
				return cell.str;
			}
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV getNodeVector2dValue(int node, double& x, double& y)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxvector2 || cellLen != 1)
				return false;
			else 
			{
				x = cell.vec2[0].x;
				y = cell.vec2[0].y;
				return true;
			}
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV getNodeVector3dValue(int node, double& x, double& y, double& z)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxvector3 || cellLen != 1)
				return false;
			else 
			{
				x = cell.vec3[0].x;
				y = cell.vec3[0].y;
				z = cell.vec3[0].z;
				return true;
			}
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV getNodeVector4dValue(int node, double& x, double& y, double& z, double& m)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxvector4 || cellLen != 1)
				return false;
			else 
			{
				x = cell.vec4[0].x;
				y = cell.vec4[0].y;
				z = cell.vec4[0].z;
				m = cell.vec4[0].w;
				return true;
			}
		}

		//////////////////////////////////////////////////////////////////////////
		extern "C" NGISDATA_API int NGISDATA_CALLCONV getNodeIntArrayValue(int node, int idx)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxint || cellLen <= 1 || idx<0 || idx>=cellLen)
				return 0;
			else 
				return cell.iVal[idx];
		}

		extern "C" NGISDATA_API double NGISDATA_CALLCONV getNodeRealArrayValue(int node, int idx)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxreal || cellLen <= 1 || idx<0 || idx>=cellLen)
				return 0;
			else 
				return cell.rVal[idx];
		}

		extern "C" NGISDATA_API const char* NGISDATA_CALLCONV getNodeStringArrayValue(int node, int idx)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxstring || cellLen <= 1 || idx<0 || idx>=cellLen)
				return 0;
			else 
			{
				return cell.pstr[idx];
			}
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV getNodeVector2dArrayValue(int node, int idx, double& x, double& y)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxvector2 || cellLen <= 1 || idx<0 || idx>=cellLen)
				return false;
			else 
			{
				x = cell.vec2[idx].x;
				y = cell.vec2[idx].y;
				return true;
			}
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV getNodeVector3dArrayValue(int node, int idx, double& x, double& y, double& z)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxvector3 || cellLen <= 1 || idx<0 || idx>=cellLen)
				return false;
			else 
			{
				x = cell.vec3[idx].x;
				y = cell.vec3[idx].y;
				z = cell.vec3[idx].z;
				return true;
			}
		}

		extern "C" NGISDATA_API bool NGISDATA_CALLCONV getNodeVector4dArrayValue(int node, int idx, double& x, double& y, double& z, double& m)
		{
			dx_node_t* realNode = (dx_node_t*)node;
			e_dx_type_t nodeType = realNode->dxobject->dxftable->fn_node_get_type(realNode);
			dx_cell_t cell= realNode->dxobject->dxftable->fn_node_get_data_cell(realNode);
			int cellLen = cell.length;
			if (nodeType!= e_dx_type_t::dxvector4 || cellLen <= 1 || idx<0 || idx>=cellLen)
				return false;
			else 
			{
				x  = cell.vec4[idx].x;
				y  = cell.vec4[idx].y;
				z  = cell.vec4[idx].z;
				m = cell.vec4[idx].w;
				return true;
			}
		}


		//////////////////////////////////////////////////////////////////////////

		const char* KernelType2String(e_dx_type_t pType, int len)
		{
			switch(pType)
			{
			case dxint:
				{
					if (len==1) return "int";
					else return "int_array";
				}
			case dxreal:
				{
					if (len==1) return "real";
					else return "real_array";
				}
			case dxstring:
				{
					if (len==1) return "string";
					else return "string_array";
				}
			case dxvector2:
				{
					if (len==1) return "vector2d";
					else return "vector2d_array";
				}
			case dxvector3:
				{
					if (len==1) return "vector3d";
					else return "vector3d_array";
				}
			case dxvector4:
				{
					if (len==1) return "vector4d";
					else return "vector4d_array";
				}
			case dxnode:
				return "any";
			case dxlist:
				return "list";
			case dxmap:
				return "map";
			case dxtable:
				return "table";
			}
		}

		e_dx_type_t String2KernelType(const char* kernelType)
		{
			std::string pStr = kernelType;
			if (pStr=="int" || pStr=="int_array")
				return dxint;
			else if (pStr == "real" || pStr=="real_array")
				return dxreal;
			else if (pStr == "string" || pStr == "string_array")
				return dxstring;
			else if (pStr == "vector2d" || pStr == "vector2d_array")
				return dxvector2;
			else if (pStr == "vector3d" || pStr == "vector3d_array")
				return dxvector3;
			else if (pStr == "vector4d" || pStr == "vector4d_array")
				return dxvector4;
			else if (pStr == "any")
				return dxnode;
			else if (pStr == "list")
				return dxlist;
			else if (pStr == "map")
				return dxmap;
			else if (pStr == "table")
				return dxtable;
		}

		void FormatXDO(dx_node_t* pNode, tinyxml2::XMLElement* element)
		{
			dx_object_t* dx = pNode->dxobject;
			e_dx_type_t  kernelType = dx->dxftable->fn_node_get_type(pNode);
			nxid_t       name =dx->dxftable->fn_node_get_name(pNode);
			dx_cell_t ce = dx->dxftable->fn_node_get_data_cell(pNode);
			int valueLen = ce.length;

			tinyxml2::XMLDocument* doc = element->GetDocument();
			tinyxml2::XMLElement* childEle = doc->NewElement("XDO");
			element->LinkEndChild(childEle);
			childEle->SetAttribute("name", name);
			if (kernelType == dxint)
			{
				if (valueLen ==1)
				{
					childEle->SetAttribute("kernelType", KernelType2String(kernelType, 1));
					childEle->SetAttribute("value", ce.iVal[0]);
				}
				else if (valueLen>1)
				{
					std::string valStr = "";
					for (int iVal=0; iVal<valueLen; iVal++)
					{
						char tempValChar[100];
						if (iVal!=valueLen-1)
							sprintf_s(tempValChar, "%d, ", ce.iVal[iVal]);
						else
							sprintf_s(tempValChar, "%d", ce.iVal[iVal]);
						valStr += tempValChar;
					}
					childEle->SetAttribute("kernelType", KernelType2String(kernelType, valueLen));
					childEle->SetAttribute("value", valStr.c_str());
				}
			}
			else if (kernelType == dxreal)
			{
				if (valueLen ==1)
				{
					childEle->SetAttribute("kernelType", KernelType2String(kernelType, 1));
					childEle->SetAttribute("value", ce.rVal[0]);
				}
				else if (valueLen>1)
				{
					std::string valStr = "";
					for (int iVal=0; iVal<valueLen; iVal++)
					{
						char tempValChar[100];
						if (iVal!=valueLen-1)
							sprintf_s(tempValChar, "%lf, ", ce.rVal[iVal]);
						else
							sprintf_s(tempValChar, "%lf", ce.rVal[iVal]);
						valStr += tempValChar;
					}
					childEle->SetAttribute("kernelType", KernelType2String(kernelType, valueLen));
					childEle->SetAttribute("value", valStr.c_str());
				}
			}
			else if (kernelType == dxstring)
			{
				if (valueLen ==1)
				{
					childEle->SetAttribute("kernelType", KernelType2String(kernelType, 1));
					childEle->SetAttribute("value", ce.str);
				}
				else if (valueLen>1)
				{
					std::string valStr = "";
					for (int iVal=0; iVal<valueLen; iVal++)
					{
						char tempValChar[100];
						if (iVal!=valueLen-1)
						{
							valStr += ce.pstr[iVal];
							valStr += "; ";
						}
						else
							valStr += ce.pstr[iVal];
					}
					childEle->SetAttribute("kernelType", KernelType2String(kernelType, valueLen));
					childEle->SetAttribute("value", valStr.c_str());
				}
			}
			else if (kernelType == dxvector2)
			{
				if (valueLen ==1)
				{
					char vector2dStr[100];
					sprintf_s(vector2dStr, "%lf,%lf", ce.vec2[0].x, ce.vec2[0].y);
					childEle->SetAttribute("kernelType", KernelType2String(kernelType, 1));
					childEle->SetAttribute("value", vector2dStr);
				}
				else if (valueLen>1)
				{
					std::string valStr = "";
					for (int iVal=0; iVal<valueLen; iVal++)
					{
						char tempValChar[100];
						if (iVal!=valueLen-1)
						{
							sprintf_s(tempValChar, "%lf,%lf; ", ce.vec2[iVal].x, ce.vec2[iVal].y);
						}
						else
							sprintf_s(tempValChar, "%lf,%lf", ce.vec2[iVal].x, ce.vec2[iVal].y);
						valStr += tempValChar;
					}
					childEle->SetAttribute("kernelType", KernelType2String(kernelType, valueLen));
					childEle->SetAttribute("value", valStr.c_str());
				}
			}
			else if (kernelType == dxvector3)
			{
				if (valueLen ==1)
				{
					char vector3dStr[100];
					sprintf_s(vector3dStr, "%f,%f,%f", ce.vec3[0].x, ce.vec3[0].y, ce.vec3[0].z);
					childEle->SetAttribute("kernelType", KernelType2String(kernelType, 1));
					childEle->SetAttribute("value", vector3dStr);
				}
				else if (valueLen>1)
				{
					std::string valStr = "";
					for (int iVal=0; iVal<valueLen; iVal++)
					{
						char tempValChar[100];
						if (iVal!=valueLen-1)
						{
							sprintf_s(tempValChar, "%lf,%lf,%lf; ", ce.vec3[iVal].x, ce.vec3[iVal].y, ce.vec3[iVal].z);
						}
						else
							sprintf_s(tempValChar, "%lf,%lf,%lf", ce.vec3[iVal].x, ce.vec3[iVal].y, ce.vec3[iVal].z);
						valStr += tempValChar;
					}
					childEle->SetAttribute("kernelType", KernelType2String(kernelType, valueLen));
					childEle->SetAttribute("value", valStr.c_str());
				}
			}
			else if (kernelType == dxvector4)
			{
				if (valueLen ==1)
				{
					char vector4dStr[100];
					sprintf_s(vector4dStr, "%f,%f,%f,%f", ce.vec4[0].x, ce.vec4[0].y, ce.vec4[0].z, ce.vec4[0].w);
					childEle->SetAttribute("kernelType", KernelType2String(kernelType, 1));
					childEle->SetAttribute("value", vector4dStr);
				}
				else if (valueLen>1)
				{
					std::string valStr = "";
					for (int iVal=0; iVal<valueLen; iVal++)
					{
						char tempValChar[100];
						if (iVal!=valueLen-1)
						{
							sprintf_s(tempValChar, "%lf,%lf,%lf,%lf; ", ce.vec4[iVal].x, ce.vec4[iVal].y, ce.vec4[iVal].z, ce.vec4[iVal].w);
						}
						else
							sprintf_s(tempValChar, "%lf,%lf,%lf,%lf", ce.vec4[iVal].x, ce.vec4[iVal].y, ce.vec4[iVal].z, ce.vec4[iVal].w);
						valStr += tempValChar;
					}
					childEle->SetAttribute("kernelType", KernelType2String(kernelType, valueLen));
					childEle->SetAttribute("value", valStr.c_str());
				}
			}
			else if (kernelType == dxnode ||
				kernelType == dxlist || 
				kernelType == dxmap ||
				kernelType == dxtable)
			{
				childEle->SetAttribute("kernelType", KernelType2String(kernelType, 1));

				int count = dx->dxftable->fn_node_get_length(pNode);
				for (int iNode=0; iNode<count; iNode++)
				{
					dx_node_t* tempNode = dx->dxftable->fn_node_get_child(pNode, iNode);
					FormatXDO(tempNode, childEle);
				}
			}
		}


		extern "C" NGISDATA_API int NGISDATA_CALLCONV formatToXmlFile(int dxObj, const char* filePath)
		{
			dx_object_t* realDx = (dx_object_t*)dxObj;

			tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
			tinyxml2::XMLElement* element = doc->NewElement("dataset");
			doc->LinkEndChild(element);

			int count = realDx->dxftable->fn_node_get_length(realDx->node);
			for (int iNode=0; iNode<count; iNode++)
			{
				dx_node_t* tempNode = realDx->dxftable->fn_node_get_child(realDx->node, iNode);
				FormatXDO(tempNode, element);
			}
	
			doc->SaveFile(filePath);
			delete doc;

			return 0;
		}


		void split(const std::string& s, const std::string& delim, std::vector<std::string>* ret) 
		{  
			size_t last = 0;   
			size_t index=s.find_first_of(delim,last);  
			while (index!=std::string::npos)  
			{   
				ret->push_back(s.substr(last,index-last));   
				last=index+1;    
				index=s.find_first_of(delim,last);  
			}   
			if (index-last>0)  
			{     
				ret->push_back(s.substr(last,index-last));
			}
		}

		void ParseXDO(dx_node_t* containerNode, tinyxml2::XMLElement* element, 
			onReturnAddChildNode callback_onReturnAddChildNode, 
			onPushNode callback_onPushNode, 
			onPopNode callback_onPopNode)
		{
			dx_object_t* dx = containerNode->dxobject;

			std::string typeStr = element->Attribute("kernelType");
			const char* name = element->Attribute("name");
			e_dx_type_t kernelType = String2KernelType(typeStr.c_str());

			if (typeStr == "int")
			{
				int val = element->IntAttribute("value");
				int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, 1);
				//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, 1);
				dx_node_t* nx = (dx_node_t*)objId;
				dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
				*cell.iVal = val;
			}
			else if (typeStr == "real")
			{
				double val = element->DoubleAttribute("value");
				int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, 1);
				//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, 1);
				dx_node_t* nx = (dx_node_t*)objId;
				dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
				*cell.rVal = val;
			}
			else if (typeStr == "string")
			{
				const char* val = element->Attribute("value");
				int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, 1);
				//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, 1);
				dx_node_t* nx = (dx_node_t*)objId;
				dx->dxftable->fn_put_string(nx, val, 0);
			}
			else if (typeStr == "vector2d")
			{
				const char* valStr = element->Attribute("value");
				double x, y;
				sscanf_s(valStr, "%lf,%lf", &x, &y);

				int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, 1);
				//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, 1);
				dx_node_t* nx = (dx_node_t*)objId;
				dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
				cell.vec2[0].x = x;
				cell.vec2[1].y = y;
			}
			else if (typeStr == "vector3d")
			{
				const char* valStr = element->Attribute("value");
				double x, y, z;
				sscanf_s(valStr, "%lf,%lf,%lf", &x, &y, &z);

				int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, 1);
				//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, 1);
				dx_node_t* nx = (dx_node_t*)objId;
				dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
				cell.vec3[0].x = x;
				cell.vec3[1].y = y;
				cell.vec3[2].z = z;
			}
			else if (typeStr == "vector4d")
			{
				const char* valStr = element->Attribute("value");
				double x, y, z, m;
				sscanf_s(valStr, "%lf,%lf,%lf,%lf", &x, &y, &z, &m);

				int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, 1);
				//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, 1);
				dx_node_t* nx = (dx_node_t*)objId;
				dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
				cell.vec4[0].x = x;
				cell.vec4[1].y = y;
				cell.vec4[2].z = z;
				cell.vec4[3].w = m;
			}
			else if (typeStr == "int_array")
			{
				std::string valStr = element->Attribute("value");
				std::vector<std::string> ret;
				split(valStr, ",", &ret);
				int count = ret.size();
				if (count == 1)
				{
					int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, count);
					//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, count);
					dx_node_t* nx = (dx_node_t*)objId;
					dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
					*cell.iVal = atoi(ret[0].c_str());
				}
				else
				{
					int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, count);
					//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, count);
					dx_node_t* nx = (dx_node_t*)objId;
					dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
					for (int iVal=0; iVal<count; iVal++)
					{
						cell.iVal[iVal] = atoi(ret[iVal].c_str());
					}
				}
			}
			else if (typeStr == "real_array")
			{
				std::string valStr = element->Attribute("value");
				std::vector<std::string> ret;
				split(valStr, ",", &ret);
				int count = ret.size();
				if (count == 1)
				{
					int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, count);
					//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, count);
					dx_node_t* nx = (dx_node_t*)objId;
					dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
					*cell.rVal = atof(ret[0].c_str());
				}
				else
				{
					int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, count);
					//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, count);
					dx_node_t* nx = (dx_node_t*)objId;
					dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
					for (int iVal=0; iVal<count; iVal++)
					{
						cell.rVal[iVal] = atof(ret[iVal].c_str());
					}
				}
			}
			else if (typeStr == "string_array")
			{
				std::string valStr = element->Attribute("value");
				std::vector<std::string> ret;
				split(valStr, ";", &ret);
				int count = ret.size();
				if (count == 1)
				{
					int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, count);
					//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, count);
					dx_node_t* nx = (dx_node_t*)objId;
					dx->dxftable->fn_put_string(nx, ret[0].c_str(), 0);
				}
				else
				{
					int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, count);
					//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, count);
					dx_node_t* nx = (dx_node_t*)objId;
					for (int iVal=0; iVal<count; iVal++)
					{
						dx->dxftable->fn_put_string(nx, ret[iVal].c_str(), iVal);
					}
				}
			}
			else if (typeStr == "vector2d_array")
			{
				std::string valStr = element->Attribute("value");
				std::vector<std::string> ret;
				split(valStr, ";", &ret);
				int count = ret.size();
				if (count == 1)
				{
					int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, count);
					//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, count);
					dx_node_t* nx = (dx_node_t*)objId;
					dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
					double x, y;
					sscanf_s(ret[0].c_str(), "%lf,%lf", &x, &y);
					cell.vec2[0].x = x;
					cell.vec2[0].y = y;
				}
				else
				{
					int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, count);
					//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, count);
					dx_node_t* nx = (dx_node_t*)objId;
					dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
					for (int iVal=0; iVal<count; iVal++)
					{
						double x, y;
						sscanf_s(ret[iVal].c_str(), "%lf,%lf", &x, &y);
						cell.vec2[iVal].x = x;
						cell.vec2[iVal].y = y;
					}
				}
			}
			else if (typeStr == "vector3d_array")
			{
				const char* valStr = element->Attribute("value");
				std::vector<std::string> ret;
				split(valStr, ";", &ret);
				int count = ret.size();
				if (count == 1)
				{
					int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, count);
					//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, count);
					dx_node_t* nx = (dx_node_t*)objId;
					dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
					double x, y, z;
					sscanf_s(ret[0].c_str(), "%lf,%lf,%lf", &x, &y, &z);
					cell.vec3[0].x = x;
					cell.vec3[0].y = y;
					cell.vec3[0].z = z;
				}
				else
				{
					int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, count);
					//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, count);
					dx_node_t* nx = (dx_node_t*)objId;
					dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
					for (int iVal=0; iVal<count; iVal++)
					{
						double x, y, z;
						sscanf_s(ret[iVal].c_str(), "%lf,%lf,%lf", &x, &y, &z);
						cell.vec3[iVal].x = x;
						cell.vec3[iVal].y = y;
						cell.vec3[iVal].z = z;
					}
				}
			}
			else if (typeStr == "vector4d_array")
			{
				std::string valStr = element->Attribute("value");
				std::vector<std::string> ret;
				split(valStr, ";", &ret);
				int count = ret.size();
				if (count == 1)
				{
					int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, count);
					//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, count);
					dx_node_t* nx = (dx_node_t*)objId;
					dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
					double x, y, z, m;
					sscanf_s(ret[0].c_str(), "%lf,%lf,%lf,%lf", &x, &y, &z, &m);
					cell.vec4[0].x = x;
					cell.vec4[0].y = y;
					cell.vec4[0].z = z;
					cell.vec4[0].w = m;
				}
				else
				{
					int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, count);
					//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, count);
					dx_node_t* nx = (dx_node_t*)objId;
					dx_cell_t cell= dx->dxftable->fn_node_get_data_cell(nx);
					for (int iVal=0; iVal<count; iVal++)
					{
						double x, y, z, m;
						sscanf_s(ret[iVal].c_str(), "%lf,%lf,%lf,%lf", &x, &y, &z, &m);
						cell.vec4[iVal].x = x;
						cell.vec4[iVal].y = y;
						cell.vec4[iVal].z = z;
						cell.vec4[iVal].w = m;
					}
				}
			}
			else if (typeStr == "any" ||
				typeStr == "list" ||
				typeStr == "map" ||
				typeStr == "table")
			{
				int objId = callback_onReturnAddChildNode(0, name, (int)kernelType, 1);
				//int objId = env->CallIntMethod(javaClass, callbackMethod, 0, WindowsTojstring(env, name), (jint)kernelType, 1);
				dx_node_t* nx = (dx_node_t*)objId;
				callback_onPushNode();
				//env->CallVoidMethod(javaClass, method_onPushNode);
				for (tinyxml2::XMLElement* childEle = element->FirstChildElement(); childEle; childEle = childEle->NextSiblingElement())
				{
					ParseXDO(nx, childEle, callback_onReturnAddChildNode, callback_onPushNode, callback_onPopNode);
				}
				callback_onPopNode();
				//env->CallVoidMethod(javaClass, method_onPopNode);
			}
		}

		extern "C" NGISDATA_API int NGISDATA_CALLCONV loadFromXmlFile(int dxObj, const char* filePath, 
			onReturnAddChildNode callback_onReturnAddChildNode, 
			onPushNode callback_onPushNode,
			onPopNode callback_onPopNode)
		{
			dx_object_t* realDx = (dx_object_t*)dxObj;

			tinyxml2::XMLDocument doc;
			doc.LoadFile( filePath );
			tinyxml2::XMLElement* rootEle = doc.RootElement();

			for (tinyxml2::XMLElement* ele=rootEle->FirstChildElement(); ele; ele=ele->NextSiblingElement())
			{
				ParseXDO(realDx->node, ele, callback_onReturnAddChildNode, callback_onPushNode, callback_onPopNode);
			}

			return 0;
		}

		std::string globe_xml_str="";
		extern "C" NGISDATA_API const char* NGISDATA_CALLCONV formatToXmlStream(int dxObj)
		{
			dx_object_t* realDx = (dx_object_t*)dxObj;

			tinyxml2::XMLDocument doc;
			tinyxml2::XMLElement* element = doc.NewElement("dataset");
			doc.LinkEndChild(element);

			int count = realDx->dxftable->fn_node_get_length(realDx->node);
			for (int iNode=0; iNode<count; iNode++)
			{
				dx_node_t* tempNode = realDx->dxftable->fn_node_get_child(realDx->node, iNode);
				FormatXDO(tempNode, element);
			}

			tinyxml2::XMLPrinter printer;
			doc.Print( &printer );
			//std::string xml_str = printer.CStr();
			globe_xml_str = printer.CStr();
			return globe_xml_str.c_str();
		}

		extern "C" NGISDATA_API int NGISDATA_CALLCONV loadFromXmlStream(int dxObj, const char* xmlStr,
			onReturnAddChildNode callback_onReturnAddChildNode, 
			onPushNode callback_onPushNode,
			onPopNode callback_onPopNode)
		{
			dx_object_t* realDx = (dx_object_t*)dxObj;

			tinyxml2::XMLDocument doc;

			tinyxml2::XMLError error_info = doc.Parse(xmlStr);
			tinyxml2::XMLElement* rootEle = doc.RootElement();

			for (tinyxml2::XMLElement* ele=rootEle->FirstChildElement(); ele; ele=ele->NextSiblingElement())
			{
				ParseXDO(realDx->node, ele, callback_onReturnAddChildNode, callback_onPushNode, callback_onPopNode);
			}

			return 0;
		}
	}
}